#ifndef JOS_KERN_E100_H
#define JOS_KERN_E100_H
#include <inc/mmu.h>
#define E100_TX_RING_SIZE   1
#define E100_RX_RING_SIZE   E100_TX_RING_SIZE

#define E100_TX_BUFFER_SIZE 1600
#define E100_RX_BUFFER_SIZE E100_TX_BUFFER_SIZE

// Network Driver struct.
extern struct pci_func nd;

void
e100_reset_device();

void
e100_init_tx_ring();

void
e100_init_rx_ring();

// Syscall interfaces.
int
e100_ns_send(void *pkt, int len);

int
e100_ns_recv(void *pkt, int len);

struct cb {
    volatile uint16_t status;
    uint16_t cmd;
    uint32_t link;
};

struct tcb {
    volatile uint16_t status;
    uint16_t cmd;
    uint32_t link;
    uint32_t tbd_array;
    uint32_t tcb_info;
    char buffer[E100_TX_BUFFER_SIZE];
};

struct rfd {
    volatile uint16_t status;
    uint16_t cmd;
    uint32_t link;
    uint32_t reserved;
    uint32_t rfd_info;
    char rfa[E100_RX_BUFFER_SIZE];
}__attribute__((aligned(PGSIZE),packed));

// CU Macros
#define E100_SCB_CUC_NOOP           0x0
#define E100_SCB_CUC_START          0x10
#define E100_SCB_CUC_RESUME         0x20
#define E100_SCB_CUC_LOAD_BASE      0x60

// RU Macros.
#define E100_SCB_RUC_NOOP           0x0
#define E100_SCB_RUC_START          0x1
#define E100_SCB_RUC_RESUME         0x2
#define E100_SCB_RUC_DMA            0x3
#define E100_SCB_RUC_LOAD_BASE      0x6

// Status Word Macros.
#define E100_SCB_STATUS_CBIT_MASK   0x8000
#define E100_SCB_RUS_NORES_MASK     0x4 

#define E100_SCB_STATUS_CBIT_SET(word) \
        (word & E100_SCB_STATUS_CBIT_MASK)

#define E100_SCB_RUS_NORES(word) \
        (word & E100_SCB_RUS_NORES_MASK)

// CB Macros.
#define E100_SCB_CMD_SBIT           0x4000
#define E100_SCB_CMD_ELBIT          0x8000
#define E100_SCB_RX_INTR            0x48

// TCB Macros.
#define E100_TCB_CMD_TRANSMIT       0x0004

#define E100_TCB_TBD_NUMBER_MASK    0xFF
#define E100_TCB_TX_THRES_MASK      0xFF
#define E100_TCB_EOF_MASK           0x1
#define E100_TCB_ZERO_MASK          0x1
#define E100_TCB_COUNT_MASK         0x3FFF

#define E100_TCB_TBD_NUMBER_SHIFT   24
#define E100_TCB_TX_THRES_SHIFT     16
#define E100_TCB_EOF_SHIFT          15
#define E100_TCB_ZERO_SHIFT         14
#define E100_TCB_COUNT_SHIFT        0 

#define E100_TCB_TBD_NUMBER(word) \
        ((word >> E100_TCB_TBD_NUMBER_SHIFT) & E100_TCB_TBD_NUMBER_MASK)

#define E100_TCB_TX_THRES(word) \
        ((word >> E100_TCB_TX_THRES_SHIFT) & E100_TCB_TX_THRES_MASK)

#define E100_TCB_EOF(word) \
        ((word >> E100_TCB_EOF_SHIFT) & E100_TCB_EOF_MASK)

#define E100_TCB_ZERO(word) \
        ((word >> E100_TCB_ZERO_SHIFT) & E100_TCB_ZERO_MASK)

#define E100_TCB_COUNT(word) \
        ((word >> E100_TCB_COUNT_SHIFT) & E100_TCB_COUNT_MASK)

#define E100_TCB_CONST_INFO_WORD(count) \
        ((0|(0xE0 << E100_TCB_TX_THRES_SHIFT))|E100_TCB_COUNT(count))

// RFD Macros.
#define E100_TCB_CMD_RECV           0x0004

#define E100_RFD_SIZE_MASK          0x3FFF
#define E100_RFD_EOF_MASK           0x1
#define E100_RFD_FBIT_MASK          0x1
#define E100_RFD_COUNT_MASK         0x3FFF

#define E100_RFD_SIZE_SHIFT         16
#define E100_RFD_EOF_SHIFT          15
#define E100_RFD_FBIT_SHIFT         14
#define E100_RFD_COUNT_SHIFT        0

#define E100_RFD_SIZE(word) \
        ((word >> E100_RFD_SIZE_SHIFT) & E100_RFD_SIZE_MASK)

#define E100_RFD_EOF(word) \
        ((word >> E100_RFD_EOF_SHIFT) & E100_RFD_EOF_MASK)

#define E100_RFD_FBIT(word) \
        ((word >> E100_RFD_FBIT_SHIFT) & E100_RFD_FBIT_MASK)

#define E100_RFD_COUNT(word) \
        ((word >> E100_RFD_COUNT_SHIFT) & E100_RFD_COUNT_MASK)

#define E100_RFD_COUNT_INFO_WORD(count) \
        ((E100_RX_BUFFER_SIZE << E100_RFD_SIZE_SHIFT) | (count << E100_RFD_COUNT_SHIFT))

#endif	// JOS_KERN_E100_H
